package models

import (
	"strings"

	"github.com/doug-martin/goqu/v9"
	"github.com/jinzhu/copier"

	// import the dialect
	_ "github.com/doug-martin/goqu/v9/dialect/mysql"
	"github.com/sirupsen/logrus"
)

type SqlGen struct {
	Goqu goqu.DialectWrapper
}

type Option struct {
	Page      uint
	Size      uint
	Field     string
	OrderList []map[string]string
}

func NewSqlGen() *SqlGen {
	return &SqlGen{
		// look up the dialect
		Goqu: goqu.Dialect("mysql"),
	}
}

/**
 * 配置设定
 *
 */
func (m *SqlGen) Option(opts ...Option) Option {
	opt := Option{}

	for _, item := range opts {
		copier.Copy(&opt, &item)
	}

	if opt.Field == "" {
		opt.Field = "*"
	}
	return opt
}

/**
 * 批量插入
 *
 */
func (m *SqlGen) InsertSql(tableName string, data ...interface{}) (sql string, args []interface{}, err error) {
	sql, args, err = m.Goqu.Insert(tableName).Rows(data...).ToSQL()
	if err != nil {
		logrus.Error("sql err", err.Error())
		return
	}

	logrus.Debug(sql)
	return
}

/**
 * 修改
 *
 */
func (m *SqlGen) UpdateSql(tableName string, values interface{}, where goqu.Expression) (sql string, args []interface{}, err error) {
	sql, args, err = m.Goqu.Update(tableName).Set(values).Where(where).ToSQL()
	if err != nil {
		logrus.Error("sql err", err.Error())
		return
	}

	logrus.Debug(sql)
	return
}

/**
 * 删除
 *
 */
func (m *SqlGen) DeleteSql(tableName string, where goqu.Expression) (sql string, args []interface{}, err error) {
	sql, args, err = m.Goqu.Delete(tableName).Where(where).ToSQL()
	if err != nil {
		logrus.Error("sql err", err.Error())
		return
	}

	logrus.Debug(sql)
	return
}

/**
 * 获取列表
 *
 */
func (m *SqlGen) GetListSql(tableName string, where goqu.Expression, opts ...Option) (sql string, args []interface{}, err error) {
	opt := m.Option(opts...)
	model := m.Goqu.Select(opt.Field).From(tableName).Where(where)
	if opt.Page > 0 {
		model = model.Offset((opt.Page - 1) * opt.Size)
	}
	if opt.Size > 0 {
		model = model.Limit(opt.Size)
	}
	if len(opt.OrderList) > 0 {
		model = m.OrderBy(model, opt.OrderList)
	}

	sql, args, err = model.ToSQL()
	if err != nil {
		logrus.Error("sql err", err.Error())
		return
	}

	logrus.Debug(sql)
	return
}

/**
 * 获取单个数据
 *
 */
func (m *SqlGen) GetOneSql(tableName string, where goqu.Expression, opts ...Option) (sql string, args []interface{}, err error) {
	opt := m.Option(opts...)
	model := m.Goqu.Select(opt.Field).From(tableName).Where(where).Limit(1)
	if len(opt.OrderList) > 0 {
		model = m.OrderBy(model, opt.OrderList)
	}

	sql, args, err = model.ToSQL()
	if err != nil {
		logrus.Error("sql err", err.Error())
		return
	}

	logrus.Debug(sql)
	return
}

/**
 * 获取单个数据
 *
 */
func (m *SqlGen) GetCountSql(tableName string, where goqu.Expression) (sql string, args []interface{}, err error) {
	sql, args, err = m.Goqu.Select(goqu.COUNT("*").As("count")).From(tableName).Where(where).ToSQL()
	if err != nil {
		logrus.Error("sql err", err.Error())
		return
	}

	logrus.Debug(sql)
	return
}

/**
 * 组装排序
 *
 */
func (m *SqlGen) OrderBy(goquModel *goqu.SelectDataset, orderList []map[string]string) *goqu.SelectDataset {
	for _, order := range orderList {
		for field, sc := range order {
			if strings.ToLower(sc) == "desc" {
				goquModel = goquModel.OrderAppend(goqu.I(field).Desc())
			} else {
				goquModel = goquModel.OrderAppend(goqu.I(field).Asc())
			}
		}
	}
	return goquModel
}
